// 需要引入LitJSON.dll文件到项目中（Assets/Plugins/LitJSON.dll）
// 将生成的配置表文件放入到Resources目录下(因为这里是使用的Resources.Load加载资源,你可以根据项目自由修改位置)
// JsonMapper.ToObject该方法需要上述的库文件
// 请将代码和资源移动到合适的环境和位置后进行测试

using System.IO.Compression;
using System.Text;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using LitJson;

public class ReadAndUseConfigFile : MonoBehaviour
{
    /// <summary>
    /// 配置文件解密的密钥,修改为你自己的在生成时配置的密钥
    /// </summary>
    readonly static string decryptCode = "DefaultEncryptCode";

    void Start()
    {
        byte[] compressedData = Resources.Load<TextAsset>("configs.lcdat").bytes;

        // 使用GZipStream解压数据
        byte[] decompressedData = Decompress(compressedData);

        // 亦或解密
        string configText = XORDecrypt(Encoding.UTF8.GetString(decompressedData));

        // 解析成游戏配置表的对象
        // 如果解密的密钥与加密时不一样则Json解析时可能会出错
        ObjectsToLcdat datas = JsonMapper.ToObject<ObjectsToLcdat>(configText);

        Debug.Log("======================================");
        Debug.Log(configText);
        Debug.Log("输出map_building_object表格中第一个数据的名字：" + datas.map_building_object[0].name);
        Debug.Log("输出map_building_object表格中第一个数据的ID：" + datas.map_building_object[0].identifier);
        Debug.Log("输出map_building_map_size表格中第一个数据的名字：" + datas.map_building_map_size[2].name);
        Debug.Log("输出map_building_map_size表格中第一个数据的ID：" + datas.map_building_map_size[2].id);
    }

    /// <summary>
    /// 解压缩配置文件
    /// </summary>
    /// <param name="compressedData">读取到的配置文件数据</param>
    /// <returns></returns>
    private static byte[] Decompress(byte[] compressedData)
    {
        using var memoryStream = new MemoryStream(compressedData);
        using var gzipStream = new GZipStream(memoryStream, CompressionMode.Decompress);
        using var resultStream = new MemoryStream();
        gzipStream.CopyTo(resultStream);
        return resultStream.ToArray();
    }

    /// <summary>
    /// 亦或解密数据
    /// </summary>
    /// <param name="ciphertext">密文</param>
    /// <param name="decryptCode">加密时使用的密钥</param>
    /// <returns></returns>
    private static string XORDecrypt(string ciphertext)
    {
        if (string.IsNullOrEmpty(decryptCode)) return ciphertext;

        StringBuilder decryptedText = new();
        int decryptCodeLen = decryptCode.Length;
        for (int i = 0; i < ciphertext.Length; i++)
        {
            char decryptedChar = (char)(ciphertext[i] ^ decryptCode[i % decryptCodeLen]);
            decryptedText.Append(decryptedChar);
        }
        return decryptedText.ToString();
    }
}


#region Excel配置表对应的游戏对象的类

/// <summary>
/// 策划表游戏配置的总对象数据!如果有的数据全为默认值,但是配置表又有配置数据
/// 那么请检查类中定义的字段是否和配置表相同,如果不同,数据会映射失败
/// </summary>
public class ObjectsToLcdat
{
    public List<ProcessPlot> process_plot;
    public List<MapBuildingObject> map_building_object;
    public List<MapBuildingCategory> map_building_category;
    public List<MapBuildingMapSize> map_building_map_size;
}


/*****************************************************
* ---佛祖保佑-永不宕机-永无BUG---
*   功能           根据策划表自动生成的C#脚本,请自行修改类型,不要直接替换!
*                  即number,list和object类型

*   作者           杉木说
*   时间           2023.8.06
*******************************************************/

// 主机名字: AnyidealsHome
// 系统CPU的架构: x64
// 操作系统: Windows_NT
// 操作系统名: win32
// 操作系统发行版本: 10.0.22621
// 自动生成时间: 2023年08月27日 11:49:19

/// <summary>
/// 策划表自动生成类 -->> map_building.xlsx object
/// </summary>
public class MapBuildingObject
{
    // MBO唯一标识
    public int identifier;
    // 名字
    public string name;
    // 是Tile?
    public bool isTIle;
    // 占地面积-Tile可不写,默认为 0#0,0#0,0
    public string floorSpace;
    // 镜像道具(X或Y镜像不可同时配置,Tile无须配置)
    public string mirrorXOrY;
    // 放置上限,-1为无限制，Tile不用设置
    public int limitCount;
    // 在编辑地图道具列表中隐藏此道具
    public bool hideInList;
    // 在游戏中倾斜道具,Tile设置无效
    public bool inclineInGame;
    // 是否出现在在游戏中的选择摆放道具阶段的列表中
    public bool showInChoosing;
    // 道具列表分类
    // 0.Tile 1.Prop 2.Scenery 3.Gear 4.Official 5.Other 
    public int listCategory;
    // 摆放层级
    // 0.Background 1.Default 2.Decoration 3.Prefab
    public int placedLayer;
    // 资源地址
    public string assetsPath;
    // 菜单中显示的精灵地址
    public string menuSpritePath;
    // 选择道具界面中显示的精灵地址
    public string choosingSpritePath;
}

/// <summary>
/// 策划表自动生成类 -->> map_building.xlsx map_size
/// </summary>
public class MapBuildingMapSize
{
    // 地图大小的id
    public int id;
    // 地图大小的名字
    public string name;
    // 地图x最小值
    public int xMin;
    // 地图x最大值
    public int xMax;
    // 地图y最小值
    public int yMin;
    // 地图y最大值
    public int yMax;
    // 玩家可移动的范围,地图x轴的宽度需要减去的值
    public int moveClampWidth;
    // 玩家可移动的范围,地图y轴的高度需要减去的值
    public int moveClampHeight;
}

/// <summary>
/// 策划表自动生成类 -->> map_building.xlsx category
/// </summary>
public class MapBuildingCategory
{
    // MBC唯一标识
    public int identifier;
    // 分类名字
    public string name;
    // 是否显示
    public bool isShow;
    // 道具列表分类
    // 0.Tile 1.Prop 2.Scenery 3.Gear 4.Official 5.Other 
    public int listCategory;
    // 在地图编辑道具列表中的排序(1005不显示)
    public int silblingIndex;
    // 在地图编辑道具列表中图标的地址
    public string menuSpritePath;
}

/// <summary>
/// 策划表自动生成类 -->> process.xlsx plot
/// </summary>
public class ProcessPlot
{
    // 剧情id
    public int id;
    // 剧情章节
    public int chapter;
    // 联合起来成为可以选择的剧情
    public int combine;
    // 下个剧情id
    public int next;
    // 剧情类型: 0->主线剧情 2->支线剧情 0->隐藏剧情
    public int type;
    // 剧情触发条件
    public List<object> trigger;
    // 谁说的话
    public string who;
    // 对话内容
    public string content;
    // 使用哪个立绘表示当前角色
    public int whoIcon;
    // 角色立绘的位置: 0->左边 1-> 中间 2->右边
    public int whoPosition;
    // 剧情奖励
    public List<object> rewards;
    // 剧情配音
    public string dub;
}

#endregion

